﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using FlexFlow;
using FlexFlow.Model;
using System.IO;
using FlexFlow.Base;
using System.Web;
using System.Threading;
using FlexFlow.Base.File;

namespace FlexFlow.Runtime.BuildService
{
    /// <summary>
    /// 该类提供了流程安装器的实现
    /// </summary>
    public class ProcessInstaller : ManagerBase
    {
        private Task installTask;
        private WorkFlowProcessIntaller installer;

        private NotificationCatalogFactory catInfoFactory = new NotificationCatalogFactory()
        {
            Sender = "流程安装器",
            DefaultDescription = "流程安装通知",
            DefaultType = NotificationType.Info
        };
        /// <summary>
        /// 获取或设置默认的表单模板编译器
        /// </summary>
        public static ProcessInstaller Default { get; set; }

        /// <summary>
        /// 安装大循环
        /// </summary>
        private void InstallAll()
        {
            while (true)
            {
                Process proc = this.Components.ProcessProvider.GetAndSetState();
                if (proc == null)
                {
                    Thread.Sleep(1000);
                }
                else
                {
                    InstallOne(proc);
                }

            }
        }
        /// <summary>
        /// 安装一个流程
        /// </summary>
        /// <param name="proc">
        /// 要安装的流程
        /// </param>
        private void InstallOne(Process proc)
        {
            FileDescription fileDes = null;
            NotificationCatalog catalog = catInfoFactory.CreateCatalog(proc.Installer);
            try
            {
                if (proc == null)
                {
                    return;
                }

                fileDes = this.Components.FileDescriptionProvider.Get(proc.PhysicalFileId);
                if (fileDes == null)
                {
                    this.Components.FormTemplateProvider.UpdateState(proc.Identity, FormTemplateState.Error, "指定文件描述不存在！");

                    NotificationManager.Default.SendNotification(catalog,
                        "流程安装失败", "您请求安装的流程 " + proc.Name + "安装失败：\n" +
                        "指定文件描述不存在！\n" +
                        "可能原因为：\n" +
                        "指定文件已在编译前删除\n" +
                        "请求的文件描述ID：" + proc.PhysicalFileId + "\n"
                        );
                }

                this.Components.FileDescriptionProvider.UpdateTag(fileDes.Identity, "Info:正在安装");

                using (Stream tempStream = this.Components.PhysicalFileManager.OpenFile(fileDes, FileOpenMode.Read))
                {
                    if (tempStream == null)
                    {
                        NotificationManager.Default.SendNotification(catalog,
                            "流程安装失败", "您请求安装的流程 " + proc.Name + "安装失败：\n" +
                            "打开模板源文件失败！\n" +
                            "可能原因为：\n" +
                            "指定文件已在安装前删除\n" +
                            "请求的文件描述ID：" + proc.PhysicalFileId + "\n"
                            );
                        throw new IOException("打开模板源文件失败！");
                    }

                    using (StreamReader reader = new StreamReader(tempStream))
                    {
                        string jsonString = reader.ReadToEnd();
                        //安装流程
                        installer.Install(jsonString, proc);
                        //处理流程权限设定
                        Activity startAct = proc.Activitys.FirstOrDefault(m => m.Identity == proc.StartActivity);
                        //有权限发起流程的人员与组织机构
                        Guid[] procUserIds = startAct.Operators.Split(',').Select(m => Guid.Parse(m)).ToArray();
                        Guid[] procOrgIds = startAct.Organizations.Split(',').Select(m => Guid.Parse(m)).ToArray();
                        //为操作人员加入权限
                        PermissionManager.Default.SetPermission(SystemPermissions.ProcessEnterPermission, procUserIds, procOrgIds, proc.Identity.ToString(), true);
                        proc.State = ProcessState.Installed;
                        if (!this.Components.ProcessProvider.Update(proc))
                        {
                            NotificationManager.Default.SendNotification(catalog,
                            "流程安装失败", "您请求安装的流程 " + proc.Name + "安装失败：\n" +
                            "写入安装后的流程到数据库失败！\n" +
                            "可能原因为：\n" +
                            "数据库已关闭\n" +
                            "请求的文件描述ID：" + proc.PhysicalFileId + "\n"
                            );
                        }

                    }
                    //conventer.ConventWordToCsHtml(tempStream, CompiledFormSavePath + @"\" + proc.Identity + ".cshtml");
                }
                if (!this.Components.FileDescriptionProvider.UpdateTag(fileDes.Identity, "Success:已安装"))
                {
                    this.Components.ProcessProvider.UpdateState(proc.Identity, ProcessState.Installed, "安装成功，但未能成功设置源文件备注");
                    NotificationManager.Default.SendNotification(catalog,
                        "表单编译警告", "您请求编译的表单 " + proc.Name + "编译成功，但是出现警告：\n" +
                        "编译成功，但未能成功设置源文件备注！\n" +
                        "可能原因为：\n" +
                        "指定文件已在编译后设置备注前删除\n" +
                        "请求的文件描述ID：" + proc.PhysicalFileId + "\n"
                        );
                }
                else
                {
                    this.Components.ProcessProvider.UpdateState(proc.Identity, ProcessState.Installed, "安装成功");
                    NotificationManager.Default.SendNotification(catalog,
                        "流程安装成功", "您请求安装的流程 " + proc.Name + "安装成功！\n" +
                        "安装后的流程名称：" + proc.Name + "\n" +
                        "请求的文件描述ID：" + proc.PhysicalFileId + "\n"
                        );
                }
            }
            catch (Exception ex)
            {
#if DEBUG
                throw ex;
#else
                this.Components.ProcessProvider.UpdateState(proc.Identity, ProcessState.Error, "安装出错：" + ex.Message);
                if (fileDes != null)
                    this.Components.FileDescriptionProvider.UpdateTag(fileDes.Identity, "Danger:安装失败:" + ex.Message);
                NotificationManager.Default.SendNotification(catalog,
                        "流程安装出错", "您请求安装的流程 " + proc.Name + "安装出现未知错误：\n" +
                        ex.Message + "\n" +
                        "可能原因为：\n" +
                        "文件格式不符合规定或者操作违规\n" +
                        "请求的文件描述ID：" + proc.PhysicalFileId + "\n"
                        );
#endif
            }

        }
        /// <summary>
        /// 开始编译线程
        /// </summary>
        public void Start()
        {
            if (installTask == null)
            {
                installTask = new Task(InstallAll);
            }
            switch (installTask.Status)
            {

                case TaskStatus.Canceled:
                case TaskStatus.Faulted:
                case TaskStatus.RanToCompletion:
                    installTask.Dispose();
                    installTask = null;
                    Start();
                    break;
                case TaskStatus.Running:
                    break;
                case TaskStatus.WaitingForActivation:
                case TaskStatus.WaitingForChildrenToComplete:
                    Thread.Sleep(100);
                    Start();
                    break;
                case TaskStatus.Created:
                    installTask.Start();
                    break;
                case TaskStatus.WaitingToRun:
                    break;
                default:
                    break;
            }
        }

        public ProcessInstaller()
        {
            this.installer = new WorkFlowProcessIntaller(this.Components.ApplicationPool);
        }
        /// <summary>
        /// 初始化表单模板编译器的静态变量
        /// </summary>
        static ProcessInstaller()
        {
            Default = new ProcessInstaller();
            Default.Start();
        }

    }
}
